package com.axend.aerosense.common.connect.ble;

import com.axend.aerosense.common.bean.RadarType;
import com.axend.aerosense.common.connect.bean.BleMsgEntity;
import com.axend.aerosense.common.connect.bean.BleMsgTag;
import com.axend.aerosense.common.connect.bean.BleNotifyEntity;
import com.blankj.utilcode.util.LogUtils;

import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 蓝牙消息处理器管理器
 */
public class BleHandlerManager {

    private ConcurrentHashMap<BleMsgTag, AbstractBleMsgProcessor> bleMsgHandlerMap = new ConcurrentHashMap<>();

    /** 添加处理器 */
    public void addHandler(AbstractBleMsgProcessor...bleMsgCodecs){
        if (null == bleMsgCodecs) {
            LogUtils.w("bleMsgCodecs is null");
            return;
        }

        for (AbstractBleMsgProcessor msgCodec : bleMsgCodecs) {
            addHandler(msgCodec);
        }
    }

    /** 添加处理器 */
    public void addHandler(AbstractBleMsgProcessor bleMsgCodec){
        if (null == bleMsgCodec) {
            LogUtils.w("bleMsgCodec is null");
            return;
        }
        bleMsgHandlerMap.put(bleMsgCodec.getMsgTag(), bleMsgCodec);
    }

    /** 获取处理器 */
    public AbstractBleMsgProcessor getHandler(BleMsgTag bleMsgTag){
        if (null == bleMsgTag) {
            return null;
        }

        return bleMsgHandlerMap.get(bleMsgTag);
    }

    /** 移除处理器 */
    public void removeHandler(BleMsgTag bleMsgTag){
        if (null == bleMsgTag) {
            LogUtils.w("bleMsgTag is null");
            return;
        }

        bleMsgHandlerMap.remove(bleMsgTag);
    }

    public void release(){
        if (null == bleMsgHandlerMap || bleMsgHandlerMap.size() == 0) {
            return;
        }

        bleMsgHandlerMap.clear();
    }

    /**
     * 获取编码后的数据
     * @param bleMsgEntity
     * @return
     */
    public byte[] getWriteBleMsg(BleMsgEntity bleMsgEntity){
        if (null == bleMsgEntity) {
            LogUtils.w("bleMsgEntity is null");
            return new byte[0];
        }
        AbstractBleMsgProcessor handler = getHandler(bleMsgEntity.getTag());
        return handler.write(bleMsgEntity);
    }

    /**
     * 处理消息，并找到对应的消息处理器
     * @param data
     */
    public BleNotifyEntity decode(byte[] data){
        if (null == data || data.length == 0) {
            LogUtils.w("data is null", data);
            return null;
        }

        int dataLength = data.length;
        if (dataLength > 1) {
            //此处为雷达板子协议的数据
            return findProcessorHandler(data);
        } else {
            //此处为通讯板子协议的数据
            AbstractBleMsgProcessor handler = getHandler(BleMsgTag.SET_STATUS);
            if (null == handler) {
                LogUtils.w("not found handler");
                return null;
            }
            BleNotifyEntity notifyEntity = new BleNotifyEntity(BleMsgTag.SET_STATUS, data);
            return handler.processor(notifyEntity);
        }
    }

    private BleNotifyEntity findProcessorHandler(byte[] data){
        ByteBuffer buffer = ByteBuffer.wrap(data);
        byte magic = buffer.get();
        //获取魔术位
        RadarType radarType = RadarType.getMagic(magic);
        //魔术位不存在，不解析协议
        if (null != radarType) {
            //移动到tag位前面
            buffer.position(14);
            short tag = buffer.getShort();
            BleMsgTag bleMsgTag = BleMsgTag.fromTag(tag);
            AbstractBleMsgProcessor handler = getHandler(bleMsgTag);
            if (null == handler) {
                LogUtils.w("not found handler");
                return null;
            }

            //截取tag位之后的数据
            int size = buffer.limit() - buffer.position();
            if (size <= 0) {
                LogUtils.w("buffer readable content length is 0");
                return null;
            }
            byte[] body = new byte[size];
            buffer.get(body);
            BleNotifyEntity notifyEntity = new BleNotifyEntity(bleMsgTag, radarType, body);
            return handler.processor(notifyEntity);
        } else {
            LogUtils.d("magic undefined", data);
        }
        return null;
    }
}
